home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume15 / cshar / part02 < prev    next >
Encoding:
Internet Message Format  |  1988-05-26  |  43.7 KB

  1. Subject:  v15i019:  Tools to create and unpack shell archives, Part02/03
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Rich Salz <rsalz@bbn.com>
  7. Posting-number: Volume 15, Issue 19
  8. Archive-name: cshar/part02
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 2 (of 3)."
  17. # Contents:  dir.amiga findsrc.c makekit.c shar.c unshar.c
  18. # Wrapped by rsalz@fig.bbn.com on Fri May 27 14:15:08 1988
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'dir.amiga' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'dir.amiga'\"
  22. else
  23. echo shar: Extracting \"'dir.amiga'\" \(6596 characters\)
  24. sed "s/^X//" >'dir.amiga' <<'END_OF_FILE'
  25. X
  26. X[  I have not tried this at all.  --r$  ]
  27. X
  28. Return-Path: mwm@violet.Berkeley.EDU
  29. Received: from violet.berkeley.edu (violet.berkeley.edu.ARPA) by PINEAPPLE.BBN.COM (4.12/4.7)  id AA28194; Tue, 14 Jul 87 00:52:17 edt
  30. Received: from localhost.ARPA
  31. X    by violet.berkeley.edu (5.54 (CFC 4.22.3)/1.16.15)
  32. X    id AA16462; Mon, 13 Jul 87 21:54:26 PDT
  33. Message-Id: <8707140454.AA16462@violet.berkeley.edu>
  34. To: Richard Salz <rsalz@pineapple.bbn.com>
  35. Subject: Re: Amiga version of the dir library... 
  36. Ultrix: Just say No!
  37. In-Reply-To: Your message of Wed, 08 Jul 87 21:19:51 -0400
  38. Date: Mon, 13 Jul 87 21:54:25 PDT
  39. XFrom: Mike (My watch has windows) Meyer <mwm@violet.Berkeley.EDU>
  40. X
  41. Here's what I did. This is built to reflect the 4BSD manual pages, not
  42. the SysV/dpANS manual pages.
  43. X
  44. I now know how to get the telldir/seekdir pair to work correctly with
  45. multiple tell()s, but don't have much motivation to do so. If someone
  46. out there does it, or is interested in doing it, I'd be interested in
  47. the results or willing to help.
  48. X
  49. XFinal note: as with many micros, there's more than one C compiler.
  50. This was written for the Lattice compiler, and uses features known
  51. not to exist in other Amiga compilers. Fixing it should be trivial.
  52. X
  53. Oh, yeah - sorry for the delay in getting these two you.
  54. X
  55. X    <mike
  56. X
  57. X#! /bin/sh
  58. X# This is a shell archive, meaning:
  59. X# 1. Remove everything above the #! /bin/sh line.
  60. X# 2. Save the resulting text in a file.
  61. X# 3. Execute the file with /bin/sh (not csh) to create:
  62. X#    dir.h
  63. X#    ndir.c
  64. X# By:    Mike (My watch has windows) Meyer (Missionaria Phonibalonica)
  65. export PATH; PATH=/bin:/usr/bin:$PATH
  66. echo shar: "extracting 'dir.h'" '(1708 characters)'
  67. if test -f 'dir.h'
  68. then
  69. X    echo shar: "will not over-write existing file 'dir.h'"
  70. else
  71. sed 's/^X//' << \SHAR_EOF > 'dir.h'
  72. XX#ifndef DIR_H
  73. XX#define DIR_H
  74. XX
  75. XX#ifndef    EXEC_TYPES_H
  76. XX#include "exec/types.h"
  77. XX#endif
  78. XX
  79. XX#ifndef    LIBRARIES_DOS_H
  80. XX#include "libraries/dos.h"
  81. XX#endif
  82. XX
  83. XX#ifndef    LIBRARIES_DOSEXTENS_H
  84. XX#include "libraries/dosextens.h"
  85. XX#endif
  86. XX/*
  87. XX * MAXNAMELEN is the maximum length a file name can be. The direct structure
  88. XX * is lifted form 4BSD, and has not been changed so that code which uses
  89. XX * it will be compatable with 4BSD code. d_ino and d_reclen are unused,
  90. XX * and will probably be set to some non-zero value.
  91. XX */
  92. XX#define    MAXNAMLEN    31        /* AmigaDOS file max length */
  93. XX
  94. XXstruct    direct {
  95. XX    ULONG    d_ino ;            /* unused - there for compatability */
  96. XX    USHORT    d_reclen ;        /* ditto */
  97. XX    USHORT    d_namlen ;        /* length of string in d_name */
  98. XX    char    d_name[MAXNAMLEN + 1] ;    /* name must be no longer than this */
  99. XX};
  100. XX/*
  101. XX * The DIRSIZ macro gives the minimum record length which will hold
  102. XX * the directory entry.  This requires the amount of space in struct direct
  103. XX * without the d_name field, plus enough space for the name with a terminating
  104. XX * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
  105. XX */
  106. XX
  107. XX#undef DIRSIZ
  108. XX#define DIRSIZ(dp) \
  109. XX    ((sizeof(struct direct) - (MAXNAMLEN+1)) + (((dp) -> d_namlen+1 + 3) &~ 3))
  110. XX/*
  111. XX * The DIR structure holds the things that AmigaDOS needs to know about
  112. XX * a file to keep track of where it is and what it's doing.
  113. XX */
  114. XX
  115. XXtypedef struct {
  116. XX    struct FileInfoBlock    d_info ,    /* Default info block */
  117. XX                d_seek ;    /* Info block for seeks */
  118. XX    struct FileLock        *d_lock ;    /* Lock on directory */
  119. XX    } DIR ;
  120. XX    
  121. XXextern    DIR *opendir(char *) ;
  122. XXextern    struct direct *readdir(DIR *) ;
  123. XXextern    long telldir(DIR *) ;
  124. XXextern    void seekdir(DIR *, long) ;
  125. XXextern    void rewinddir(DIR *) ;
  126. XXextern    void closedir(DIR *) ;
  127. XX#endif    DIR_H
  128. SHAR_EOF
  129. if test 1708 -ne "`wc -c < 'dir.h'`"
  130. then
  131. X    echo shar: "error transmitting 'dir.h'" '(should have been 1708 characters)'
  132. fi
  133. fi
  134. echo shar: "extracting 'ndir.c'" '(2486 characters)'
  135. if test -f 'ndir.c'
  136. then
  137. X    echo shar: "will not over-write existing file 'ndir.c'"
  138. else
  139. sed 's/^X//' << \SHAR_EOF > 'ndir.c'
  140. XX/*
  141. XX * ndir - routines to simulate the 4BSD new directory code for AmigaDOS.
  142. XX */
  143. XX#include <dir.h>
  144. XX
  145. XXDIR *
  146. XXopendir(dirname) char *dirname; {
  147. XX    register DIR    *my_dir, *AllocMem(int, int) ;
  148. XX    struct FileLock    *Lock(char *, int), *CurrentDir(struct FileLock *) ;
  149. XX
  150. XX    if ((my_dir = AllocMem(sizeof(DIR), 0)) == NULL) return NULL ;
  151. XX
  152. XX
  153. XX    if (((my_dir -> d_lock = Lock(dirname, ACCESS_READ)) == NULL)
  154. XX    /* If we can't examine it */
  155. XX    ||  !Examine(my_dir -> d_lock, &(my_dir -> d_info))
  156. XX    /* Or it's not a directory */
  157. XX    ||  (my_dir -> d_info . fib_DirEntryType < 0)) {
  158. XX        FreeMem(my_dir, sizeof(DIR)) ;
  159. XX        return NULL ;
  160. XX        }
  161. XX    return my_dir ;
  162. XX    }
  163. XX
  164. XXstruct direct *
  165. XXreaddir(my_dir) DIR *my_dir; {
  166. XX    static struct direct    result ;
  167. XX
  168. XX    if (!ExNext(my_dir -> d_lock, &(my_dir -> d_info))) return NULL ;
  169. XX
  170. XX    result . d_reclen = result . d_ino = 1 ;    /* Not NULL! */
  171. XX    (void) strcpy(result . d_name, my_dir -> d_info . fib_FileName) ;
  172. XX    result . d_namlen = strlen(result . d_name) ;
  173. XX    return &result ;
  174. XX    }
  175. XX
  176. XXvoid
  177. XXclosedir(my_dir) DIR *my_dir; {
  178. XX
  179. XX    UnLock(my_dir -> d_lock) ;
  180. XX    FreeMem(my_dir, sizeof(DIR)) ;
  181. XX    }
  182. XX/*
  183. XX * telldir and seekdir don't work quite right. The problem is that you have
  184. XX * to save more than a long's worth of stuff to indicate position, and it's
  185. XX * socially unacceptable to alloc stuff that you don't free later under
  186. XX * AmigaDOS. So we fake it - you get one level of seek, and dat's all.
  187. XX * As of now, these things are untested.
  188. XX */
  189. XX#define DIR_SEEK_RETURN        ((long) 1)    /* Not 0! */
  190. XXlong
  191. XXtelldir(my_dir) DIR *my_dir; {
  192. XX
  193. XX    my_dir -> d_seek = my_dir -> d_info ;
  194. XX    return (long) DIR_SEEK_RETURN ;
  195. XX    }
  196. XX
  197. XXvoid
  198. XXseekdir(my_dir, where) DIR *my_dir; long where; {
  199. XX
  200. XX    if (where == DIR_SEEK_RETURN)
  201. XX        my_dir -> d_info = my_dir -> d_seek ;
  202. XX    else    /* Makes the next readdir fail */
  203. XX        setmem((char *) my_dir, sizeof(DIR), 0) ;
  204. XX    }
  205. XX
  206. XXvoid
  207. XXrewinddir(my_dir) DIR *my_dir; {
  208. XX
  209. XX    if (!Examine(my_dir -> d_lock, &(my_dir -> d_info)))
  210. XX        setmem((char *) my_dir, sizeof(DIR), 0) ;
  211. XX    }
  212. XX#ifdef    TEST
  213. XX/*
  214. XX * Simple code to list the files in the argument directory,
  215. XX *    lifted straight from the man page.
  216. XX */
  217. XX#include <stdio.h>
  218. XXvoid
  219. XXmain(argc, argv) int argc; char **argv; {
  220. XX    register DIR        *dirp ;
  221. XX    register struct direct    *dp ;
  222. XX    register char        *name ;
  223. XX
  224. XX    if (argc < 2) name = "" ;
  225. XX    else name = argv[1] ;
  226. XX
  227. XX    if ((dirp = opendir(name)) == NULL) {
  228. XX        fprintf(stderr, "Bogus! Can't opendir %s\n", name) ;
  229. XX        exit(1) ;
  230. XX        }
  231. XX
  232. XX    for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
  233. XX        printf("%s ", dp -> d_name) ;
  234. XX    closedir(dirp);
  235. XX    putchar('\n') ;
  236. XX    }
  237. XX#endif    TEST
  238. XX
  239. SHAR_EOF
  240. if test 2486 -ne "`wc -c < 'ndir.c'`"
  241. then
  242. X    echo shar: "error transmitting 'ndir.c'" '(should have been 2486 characters)'
  243. fi
  244. fi
  245. exit 0
  246. X#    End of shell archive
  247. END_OF_FILE
  248. if test 6596 -ne `wc -c <'dir.amiga'`; then
  249.     echo shar: \"'dir.amiga'\" unpacked with wrong size!
  250. fi
  251. # end of 'dir.amiga'
  252. fi
  253. if test -f 'findsrc.c' -a "${1}" != "-c" ; then 
  254.   echo shar: Will not clobber existing file \"'findsrc.c'\"
  255. else
  256. echo shar: Extracting \"'findsrc.c'\" \(7195 characters\)
  257. sed "s/^X//" >'findsrc.c' <<'END_OF_FILE'
  258. X/*
  259. X**  FINDSRC
  260. X**  Walk directories, trying to find source files.
  261. X*/
  262. X#include "shar.h"
  263. X#ifdef    RCSID
  264. static char RCS[] =
  265. X    "$Header: findsrc.c,v 2.0 88/05/27 13:26:05 rsalz Exp $";
  266. X#endif    /* RCSID */
  267. X
  268. X
  269. X/*
  270. X**  Global variables.
  271. X*/
  272. int     DoDOTFILES;            /* Do .newsrc and friends?    */
  273. int     DoRCS;                /* Do RCS and SCCS files?    */
  274. int     Default;            /* Default answer from user    */
  275. int     Verbose;            /* List rejected files, too?    */
  276. char    *Dname;                /* Filename of directory list    */
  277. char    *Fname;                /* Filename of file list    */
  278. XFILE    *Dfile;                /* List of directories found    */
  279. XFILE    *Ffile;                /* List of files found        */
  280. XFILE    *DEVTTY;            /* The tty, if in filter mode    */
  281. X
  282. X
  283. X/*
  284. X**  Signal handler.  Clean up and die.
  285. X*/
  286. static sigret_t
  287. Catch(s)
  288. X    int         s;
  289. X{
  290. X    int         e;
  291. X
  292. X    e = errno;
  293. X    if (Dname)
  294. X    (void)unlink(Dname);
  295. X    if (Fname)
  296. X    (void)unlink(Fname);
  297. X    Fprintf(stderr, "Got signal %d, %s.\n", s, Ermsg(e));
  298. X    exit(1);
  299. X}
  300. X
  301. X
  302. X/*
  303. X**  Given a filename, apply heuristics to see if we want it.
  304. X*/
  305. static int
  306. Wanted(Name)
  307. X    REGISTER char    *Name;
  308. X{
  309. X    REGISTER FILE    *F;
  310. X    REGISTER char    *s;
  311. X    REGISTER char    *p;
  312. X    REGISTER char    *d;
  313. X    char         buff[BUFSIZ];
  314. X
  315. X    /* Get down to brass tacks. */
  316. X    s = (p = RDX(Name, '/')) ? p + 1 : Name;
  317. X
  318. X    /* Only do directories other than . and .. and regular files. */
  319. X    if ((Ftype(Name) != F_DIR && Ftype(Name) != F_FILE)
  320. X     || EQ(s, ".") || EQ(s, ".."))
  321. X    return(FALSE);
  322. X
  323. X    /* Common cruft we never want. */
  324. X    if (EQ(s, "foo") || EQ(s, "core") || EQ(s, "tags") || EQ(s, "lint"))
  325. X    return(FALSE);
  326. X
  327. X    /* Disregard stuff with bogus suffixes. */
  328. X    d = RDX(s, '.');
  329. X    if ((p = d)
  330. X     && (EQ(++p, "out") || EQ(p, "orig") || EQ(p, "rej") || EQ(p, "BAK")
  331. X      || EQ(p, "CKP") || EQ(p, "old") || EQ(p, "o") || EQ(p, "EXE")
  332. X      || EQ(p, "OBJ")))
  333. X    return(FALSE);
  334. X
  335. X    /* Want .cshrc, .newsrc, etc.? */
  336. X    if (*s == '.' && isalpha(s[1]))
  337. X    return(DoDOTFILES);
  338. X
  339. X    /* RCS or SCCS file or directory? */
  340. X    if (EQ(s, "RCS")
  341. X     || ((p = RDX(s, ',')) && *++p == 'v' && *++p == '\0')
  342. X     || EQ(s, "SCCS") || (s[0] == 's' && s[1] == '.'))
  343. X    return(DoRCS);
  344. X
  345. X    /* Mlisp, m4 (yes to .m? but no to .mo)? */
  346. X    /* really, no to .mo but yes to names matching the regexp ".m?" */
  347. X    if ((p = d) && *++p == 'm' && p[2] == '\0')
  348. X    return(*++p != 'o');
  349. X
  350. X    /* Gnu Emacs elisp (yes to .el*, but no to .elc)? */
  351. X    if ((p = d) && *++p == 'e' && *++p == 'l')
  352. X    return(*++p != 'c' || *++p);
  353. X
  354. X    /* C source (*.[ch])? */
  355. X    if ((p = d) && (*++p == 'c' || *p == 'h') && *++p == '\0')
  356. X
  357. X    /* Manpage (*.[1234567890] or *.man)? */
  358. X    if ((p = d) && isdigit(*p))
  359. X    return(TRUE);
  360. X    if ((p = d) && *++p == 'm' && *++p == 'a' && *++p == 'n')
  361. X    return(TRUE);
  362. X
  363. X    /* Make control file? */
  364. X    if ((*s == 'M' || *s == 'm') && EQ(s + 1, "akefile"))
  365. X    return(TRUE);
  366. X
  367. X    /* Convert to lowercase, and see if it's a README or MANIFEST. */
  368. X    for (p = strcpy(buff, s); *p; p++)
  369. X    if (isascii(*p) && isupper(*p))
  370. X        *p = tolower(*p);
  371. X    if (EQ(buff, "readme") || EQ(buff, "read_me") || EQ(buff, "read-me")
  372. X     || EQ(buff, "manifest"))
  373. X    return(TRUE);
  374. X
  375. X    /* Larry Wall-style template file (*.SH)? */
  376. X    if ((p = d) && *++p == 'S' && *++p == 'H')
  377. X    return(TRUE);
  378. X
  379. X    /* If we have a default, give it back. */
  380. X    if (Default)
  381. X    return(Default == 'y');
  382. X
  383. X#ifdef    CAN_POPEN
  384. X    /* See what file(1) has to say; if it says executable, punt. */
  385. X    (void)sprintf(buff, "exec file '%s'", Name);
  386. X    if (F = popen(buff, "r")) {
  387. X    (void)fgets(buff, sizeof buff, F);
  388. X    (void)pclose(F);
  389. X    for (p = buff; p = IDX(p, 'e'); p++)
  390. X        if (PREFIX(p, "executable"))
  391. X        return(FALSE);
  392. X    (void)fputs(buff, stderr);
  393. X    }
  394. X#endif    /* CAN_POPEN */
  395. X
  396. X    /* Add it? */
  397. X    while (TRUE) {
  398. X    if (DEVTTY == NULL)
  399. X        DEVTTY = fopen(THE_TTY, "r");
  400. X    Fprintf(stderr, "Add this one (y or n)[y]?  ");
  401. X    (void)fflush(stderr);
  402. X    if (fgets(buff, sizeof buff, DEVTTY) == NULL
  403. X     || buff[0] == '\n' || buff[0] == 'y' || buff[0] == 'Y')
  404. X        break;
  405. X    if (buff[0] == 'n' || buff[0] == 'N')
  406. X        return(FALSE);
  407. X    if (buff[0] == '!' )
  408. X        (void)system(&buff[1]);
  409. X    Fprintf(stderr, "--------------------\n%s:  ", Name);
  410. X    clearerr(DEVTTY);
  411. X    }
  412. X    return(TRUE);
  413. X}
  414. X
  415. X
  416. X/*
  417. X**  Quick and dirty recursive routine to walk down directory tree.
  418. X**  Could be made more general, but why bother?
  419. X*/
  420. static void
  421. Process(p, level)
  422. X    REGISTER char     *p;
  423. X    REGISTER int      level;
  424. X{
  425. X    REGISTER char     *q;
  426. X    DIR             *Dp;
  427. X    DIRENTRY         *E;
  428. X    char          buff[BUFSIZ];
  429. X
  430. X#ifdef    MSDOS
  431. X    strlwr(p);
  432. X#endif    /* MSDOS */
  433. X
  434. X    if (!GetStat(p))
  435. X    Fprintf(stderr, "Can't walk down %s, %s.\n", Ermsg(errno));
  436. X    else {
  437. X    /* Skip leading ./ which find(1), e.g., likes to put out. */
  438. X    if (p[0] == '.' && p[1] == '/')
  439. X        p += 2;
  440. X
  441. X    if (Wanted(p))
  442. X        Fprintf(Ftype(p) == F_FILE ? Ffile : Dfile, "%s\n", p);
  443. X    else if (Verbose)
  444. X        Fprintf(Ftype(p) == F_FILE ? Ffile : Dfile, "PUNTED %s\n", p);
  445. X
  446. X    if (Ftype(p) == F_DIR)
  447. X        if (++level == MAX_LEVELS)
  448. X        Fprintf(stderr, "Won't walk down %s -- more than %d levels.\n",
  449. X            p, level);
  450. X        else if (Dp = opendir(p)) {
  451. X        q = buff + strlen(strcpy(buff, p));
  452. X        for (*q++ = '/'; E = readdir(Dp); )
  453. X            if (!EQ(E->d_name, ".") && !EQ(E->d_name, "..")) {
  454. X            (void)strcpy(q, E->d_name);
  455. X            Process(buff, level);
  456. X            }
  457. X        (void)closedir(Dp);
  458. X        }
  459. X        else
  460. X        Fprintf(stderr, "Can't open directory %s, %s.\n",
  461. X            p, Ermsg(errno));
  462. X    }
  463. X}
  464. X
  465. X
  466. main(ac, av)
  467. X    REGISTER int     ac;
  468. X    REGISTER char    *av[];
  469. X{
  470. X    REGISTER char    *p;
  471. X    REGISTER int     i;
  472. X    REGISTER int     Oops;
  473. X    char         buff[BUFSIZ];
  474. X
  475. X    /* Parse JCL. */
  476. X    for (Oops = 0; (i = getopt(ac, av, ".d:o:RSv")) != EOF; )
  477. X    switch (i) {
  478. X    default:
  479. X        Oops++;
  480. X        break;
  481. X    case '.':
  482. X        DoDOTFILES++;
  483. X        break;
  484. X    case 'd':
  485. X        switch (optarg[0]) {
  486. X        default:
  487. X        Oops++;
  488. X        break;
  489. X        case 'y':
  490. X        case 'Y':
  491. X        Default = 'y';
  492. X        break;
  493. X        case 'n':
  494. X        case 'N':
  495. X        Default = 'n';
  496. X        break;
  497. X        }
  498. X        break;
  499. X    case 'o':
  500. X        if (freopen(optarg, "w", stdout) == NULL) {
  501. X        Fprintf(stderr, "Can't open %s for output, %s.\n",
  502. X            optarg, Ermsg(errno));
  503. X        exit(1);
  504. X        }
  505. X    case 'R':
  506. X    case 'S':
  507. X        DoRCS++;
  508. X        break;
  509. X    case 'v':
  510. X        Verbose++;
  511. X        break;
  512. X    }
  513. X    if (Oops) {
  514. X    Fprintf(stderr, "Usage: findsrc [-d{yn}] [-.] [-{RS}] [-v] files...\n");
  515. X    exit(1);
  516. X    }
  517. X    av += optind;
  518. X
  519. X    /* Set signal catcher, open temp files. */
  520. X    SetSigs(TRUE, Catch);
  521. X    Dname = mktemp("/tmp/findDXXXXXX");
  522. X    Fname = mktemp("/tmp/findFXXXXXX");
  523. X    Dfile = fopen(Dname, "w");
  524. X    Ffile = fopen(Fname, "w");
  525. X
  526. X    /* Read list of files, determine their status. */
  527. X    if (*av)
  528. X    for (DEVTTY = stdin; *av; av++)
  529. X        Process(*av, 0);
  530. X    else
  531. X    while (fgets(buff, sizeof buff, stdin)) {
  532. X        if (p = IDX(buff, '\n'))
  533. X        *p = '\0';
  534. X        else
  535. X        Fprintf(stderr, "Warning, line too long:\n\t%s\n", buff);
  536. X        Process(buff, 0);
  537. X    }
  538. X
  539. X    /* First print directories. */
  540. X    if (freopen(Dname, "r", Dfile)) {
  541. X    while (fgets(buff, sizeof buff, Dfile))
  542. X        (void)fputs(buff, stdout);
  543. X    (void)fclose(Dfile);
  544. X    }
  545. X
  546. X    /* Now print regular files. */
  547. X    if (freopen(Fname, "r", Ffile)) {
  548. X    while (fgets(buff, sizeof buff, Ffile))
  549. X        (void)fputs(buff, stdout);
  550. X    (void)fclose(Ffile);
  551. X    }
  552. X
  553. X    /* That's all she wrote. */
  554. X    (void)unlink(Dname);
  555. X    (void)unlink(Fname);
  556. X    exit(0);
  557. X}
  558. END_OF_FILE
  559. if test 7195 -ne `wc -c <'findsrc.c'`; then
  560.     echo shar: \"'findsrc.c'\" unpacked with wrong size!
  561. fi
  562. # end of 'findsrc.c'
  563. fi
  564. if test -f 'makekit.c' -a "${1}" != "-c" ; then 
  565.   echo shar: Will not clobber existing file \"'makekit.c'\"
  566. else
  567. echo shar: Extracting \"'makekit.c'\" \(10488 characters\)
  568. sed "s/^X//" >'makekit.c' <<'END_OF_FILE'
  569. X/*
  570. X**  MAKEKIT
  571. X**  Split up source files into reasonably-sized shar lists.
  572. X*/
  573. X#include "shar.h"
  574. X#ifdef    RCSID
  575. static char RCS[] =
  576. X    "$Header: makekit.c,v 2.0 88/05/27 13:27:31 rsalz Exp $";
  577. X#endif    /* RCSID */
  578. X
  579. X
  580. X/*
  581. X**  Our block of information about the files we're doing.
  582. X*/
  583. typedef struct _block {
  584. X    char    *Name;            /* Filename            */
  585. X    char    *Text;            /* What it is            */
  586. X    int         Where;            /* Where it is            */
  587. X    int         Type;            /* Directory or file?        */
  588. X    long     Bsize;            /* Size in bytes        */
  589. X} BLOCK;
  590. X
  591. X
  592. X/*
  593. X**  Our block of information about the archives we're making.
  594. X*/
  595. typedef struct _archive {
  596. X    int         Count;            /* Number of files        */
  597. X    long     Asize;            /* Bytes used by archive    */
  598. X} ARCHIVE;
  599. X
  600. X
  601. X/*
  602. X**  Format strings; these are strict K&R so you shouldn't have to change them.
  603. X*/
  604. X#define FORMAT1        " %-25s %2d\t%s\n"
  605. X#define FORMAT2        "%s%2.2d"
  606. X#ifdef    FMT02d
  607. X#undef FORMAT2
  608. X#define FORMAT2        "%s%02.2d"    /* I spoke too soon...        */
  609. X#endif    /* FMT02d */
  610. X
  611. X
  612. X/*
  613. X**  Global variables.
  614. X*/
  615. char    *InName;            /* File with list to pack    */
  616. char    *OutName;            /* Where our output goes    */
  617. char    *SharName = "Part";        /* Prefix for name of each shar    */
  618. char    *Trailer;            /* Text for shar to pack in    */
  619. char    *TEMP;                /* Temporary manifest file    */
  620. X#ifdef    MSDOS
  621. char    *FLST;                /* File with list for shar    */
  622. X#endif    MSDOS
  623. int     ArkCount = 20;            /* Max number of archives    */
  624. int     ExcludeIt;            /* Leave out the output file?    */
  625. int     Header;            /* Lines of prolog in input    */
  626. int     Preserve;            /* Preserve order for Manifest?    */
  627. int     Working = TRUE;        /* Call shar when done?        */
  628. long     Size = 55000;            /* Largest legal archive size    */
  629. X
  630. X
  631. X/*
  632. X**  Sorting predicate to put README or MANIFEST first, then directories,
  633. X**  then larger files, then smaller files, which is how we want to pack
  634. X**  stuff in archives.
  635. X*/
  636. static int
  637. SizeP(t1, t2)
  638. X    BLOCK    *t1;
  639. X    BLOCK    *t2;
  640. X{
  641. X    long     i;
  642. X
  643. X    if (t1->Type == F_DIR)
  644. X    return(t2->Type == F_DIR ? 0 : -1);
  645. X    if (t2->Type == F_DIR)
  646. X    return(1);
  647. X    if (EQn(t1->Name, "README", 6) || (OutName && EQ(t1->Name, OutName)))
  648. X    return(-1);
  649. X    if (EQn(t2->Name, "README", 6) || (OutName && EQ(t2->Name, OutName)))
  650. X    return(1);
  651. X    return((i = t1->Bsize - t2->Bsize) == 0L ? 0 : (i < 0L ? -1 : 1));
  652. X}
  653. X
  654. X
  655. X/*
  656. X**  Sorting predicate to get things in alphabetical order, which is how
  657. X**  we write the Manifest file.
  658. X*/
  659. static int
  660. NameP(t1, t2)
  661. X    BLOCK    *t1;
  662. X    BLOCK    *t2;
  663. X{
  664. X    int         i;
  665. X
  666. X    return((i = *t1->Name - *t2->Name) ? i : strcmp(t1->Name, t2->Name));
  667. X}
  668. X
  669. X
  670. X/*
  671. X**  Skip whitespace.
  672. X*/
  673. static char *
  674. Skip(p)
  675. X    REGISTER char    *p;
  676. X{
  677. X    while (*p && WHITE(*p))
  678. X    p++;
  679. X    return(p);
  680. X}
  681. X
  682. X
  683. X/*
  684. X**  Signal handler.  Clean up and die.
  685. X*/
  686. static sigret_t
  687. Catch(s)
  688. X    int         s;
  689. X{
  690. X    int         e;
  691. X
  692. X    e = errno;
  693. X    if (TEMP)
  694. X    (void)unlink(TEMP);
  695. X#ifdef    MSDOS
  696. X    if (FLST)
  697. X    (void)unlink(FLST);
  698. X#endif    /* MSDOS */
  699. X    Fprintf(stderr, "Got signal %d, %s.\n", s, Ermsg(e));
  700. X    exit(1);
  701. X}
  702. X
  703. X
  704. main(ac, av)
  705. X    REGISTER int     ac;
  706. X    char        *av[];
  707. X{
  708. X    REGISTER FILE    *F;
  709. X    REGISTER FILE    *In;
  710. X    REGISTER BLOCK    *t;
  711. X    REGISTER ARCHIVE    *k;
  712. X    REGISTER char    *p;
  713. X    REGISTER int     i;
  714. X    REGISTER int     lines;
  715. X    REGISTER int     Value;
  716. X    BLOCK        *Table;
  717. X    BLOCK        *TabEnd;
  718. X    ARCHIVE        *Ark;
  719. X    ARCHIVE        *ArkEnd;
  720. X    char         buff[BUFSIZ];
  721. X    long         lsize;
  722. X    int             LastOne;
  723. X    int             Start;
  724. X    int             Notkits;
  725. X    char         EndArkNum[20];
  726. X    char         CurArkNum[20];
  727. X
  728. X    /* Collect input. */
  729. X    Value = FALSE;
  730. X    Notkits = FALSE;
  731. X    while ((i = getopt(ac, av, "1eh:i:k:n:mo:p:s:t:x")) != EOF)
  732. X    switch (i) {
  733. X    default:
  734. X        Fprintf(stderr,
  735. X"usage: makekit -e -s# [-m | -iMANIFEST -oMANIFEST -h2] -nName -tText files..."
  736. X            );
  737. X        exit(1);
  738. X    case '1':
  739. X        Notkits = TRUE;
  740. X        break;
  741. X    case 'e':
  742. X        ExcludeIt = TRUE;
  743. X        break;
  744. X    case 'h':
  745. X        Header = atoi(optarg);
  746. X        break;
  747. X    case 'i':
  748. X        InName = optarg;
  749. X        break;
  750. X    case 'k':
  751. X        ArkCount = atoi(optarg);
  752. X        break;
  753. X    case 'm':
  754. X        InName = OutName = "MANIFEST";
  755. X        Header = 2;
  756. X        break;
  757. X    case 'n':
  758. X        SharName = optarg;
  759. X        break;
  760. X    case 'o':
  761. X        OutName = optarg;
  762. X        break;
  763. X    case 'p':
  764. X        Preserve = TRUE;
  765. X        break;
  766. X    case 's':
  767. X        Size = atoi(optarg);
  768. X        if (IDX(optarg, 'k') || IDX(optarg, 'K'))
  769. X        Size *= 1024;
  770. X        break;
  771. X    case 't':
  772. X        Trailer = optarg;
  773. X        break;
  774. X    case 'x':
  775. X        Working = FALSE;
  776. X        break;
  777. X    }
  778. X    ac -= optind;
  779. X    av += optind;
  780. X
  781. X    /* Write the file list to a temp file. */
  782. X    TEMP = mktemp("/tmp/maniXXXXXX");
  783. X    F = fopen(TEMP, "w");
  784. X    SetSigs(TRUE, Catch);
  785. X    if (av[0])
  786. X    /* Got the arguments on the command line. */
  787. X    while (*av)
  788. X        Fprintf(F, "%s\n", *av++);
  789. X    else {
  790. X    /* Got the name of the file from the command line. */
  791. X    if (InName == NULL)
  792. X        In = stdin;
  793. X    else if ((In = fopen(InName, "r")) == NULL) {
  794. X        Fprintf(stderr, "Can't read %s as manifest, %s.\n",
  795. X            InName, Ermsg(errno));
  796. X        exit(1);
  797. X    }
  798. X    /* Skip any possible prolog, then output rest of file. */
  799. X    while (--Header >= 0 && fgets(buff, sizeof buff, In))
  800. X        ;
  801. X    if (feof(In)) {
  802. X        Fprintf(stderr, "Nothing but header lines in list!?\n");
  803. X        exit(1);
  804. X    }
  805. X    while (fgets(buff, sizeof buff, In))
  806. X        fputs(buff, F);
  807. X    if (In != stdin)
  808. X        (void)fclose(In);
  809. X    }
  810. X    (void)fclose(F);
  811. X
  812. X    /* Count number of files, allow for NULL and our output file. */
  813. X    F = fopen(TEMP, "r");
  814. X    for (lines = 2; fgets(buff, sizeof buff, F); lines++)
  815. X    ;
  816. X    rewind(F);
  817. X
  818. X    /* Read lines and parse lines, see if we found our OutFile. */
  819. X    Table = NEW(BLOCK, lines);
  820. X    for (t = Table, Value = FALSE, lines = 0; fgets(buff, sizeof buff, F); ) {
  821. X    /* Read line, skip first word, check for blank line. */
  822. X    if (p = IDX(buff, '\n'))
  823. X        *p = '\0';
  824. X    else
  825. X        Fprintf(stderr, "Warning, line truncated:\n%s\n", buff);
  826. X    p = Skip(buff);
  827. X    if (*p == '\0')
  828. X        continue;
  829. X
  830. X    /* Copy the line, snip off the first word. */
  831. X    for (p = t->Name = COPY(p); *p && !WHITE(*p); p++)
  832. X        ;
  833. X    if (*p)
  834. X        *p++ = '\0';
  835. X
  836. X    /* Skip <spaces><digits><spaces>; remainder is the file description. */
  837. X    for (p = Skip(p); *p && isdigit(*p); )
  838. X        p++;
  839. X    t->Text = Skip(p);
  840. X
  841. X    /* Get file type. */
  842. X    if (!GetStat(t->Name)) {
  843. X        Fprintf(stderr, "Can't stat %s (%s), skipping.\n",
  844. X            t->Name, Ermsg(errno));
  845. X        continue;
  846. X    }
  847. X    t->Type = Ftype(t->Name);
  848. X
  849. X    /* Guesstimate its size when archived:  prolog, plus one char/line. */
  850. X    t->Bsize = strlen(t->Name) * 3 + 200;
  851. X    if (t->Type == F_FILE) {
  852. X        lsize = Fsize(t->Name);
  853. X        t->Bsize += lsize + lsize / 60;
  854. X    }
  855. X    if (t->Bsize > Size) {
  856. X        Fprintf(stderr, "At %ld bytes, %s is too big for any archive!\n",
  857. X            t->Bsize, t->Name);
  858. X        exit(1);
  859. X    }
  860. X
  861. X    /* Is our ouput file there? */
  862. X    if (!Value && OutName && EQ(OutName, t->Name))
  863. X        Value = TRUE;
  864. X
  865. X    /* All done -- advance to next entry. */
  866. X    t++;
  867. X    }
  868. X    (void)fclose(F);
  869. X    (void)unlink(TEMP);
  870. X    SetSigs(S_RESET, (sigret_t (*)())NULL);
  871. X
  872. X    /* Add our output file? */
  873. X    if (!ExcludeIt && !Value && OutName) {
  874. X    t->Name = OutName;
  875. X    t->Text = "This shipping list";
  876. X    t->Type = F_FILE;
  877. X    t->Bsize = lines * 60;
  878. X    t++;
  879. X    }
  880. X
  881. X    /* Sort by size, get archive space. */
  882. X    lines = t - Table;
  883. X    TabEnd = &Table[lines];
  884. X    if (!Preserve)
  885. X    qsort((char *)Table, lines, sizeof Table[0], SizeP);
  886. X    Ark = NEW(ARCHIVE, ArkCount);
  887. X    ArkEnd = &Ark[ArkCount];
  888. X
  889. X    /* Loop through the pieces, and put everyone into an archive. */
  890. X    for (t = Table; t < TabEnd; t++) {
  891. X    for (k = Ark; k < ArkEnd; k++)
  892. X        if (t->Bsize + k->Asize < Size) {
  893. X        k->Asize += t->Bsize;
  894. X        t->Where = k - Ark;
  895. X        k->Count++;
  896. X        break;
  897. X        }
  898. X    if (k == ArkEnd) {
  899. X        Fprintf(stderr, "'%s' doesn't fit -- need more then %d archives.\n",
  900. X            t->Name, ArkCount);
  901. X        exit(1);
  902. X    }
  903. X    /* Since our share doesn't build sub-directories... */
  904. X    if (t->Type == F_DIR && k != Ark)
  905. X        Fprintf(stderr, "Warning:  directory '%s' is in archive %d\n",
  906. X            t->Name, k - Ark + 1);
  907. X    }
  908. X
  909. X    /* Open the output file. */
  910. X    if (OutName == NULL)
  911. X    F = stdout;
  912. X    else {
  913. X    if (GetStat(OutName)) {
  914. X        /* Handle /foo/bar/VeryLongFileName.BAK for non-BSD sites. */
  915. X        (void)sprintf(buff, "%s.BAK", OutName);
  916. X        p = (p = RDX(buff, '/')) ? p + 1 : buff;
  917. X        if (strlen(p) > 14)
  918. X        /* ... well, sort of handle it. */
  919. X        (void)strcpy(&p[10], ".BAK");
  920. X        Fprintf(stderr, "Renaming %s to %s\n", OutName, buff);
  921. X        (void)unlink(buff);
  922. X        (void)link(OutName, buff);
  923. X        (void)unlink(OutName);
  924. X    }
  925. X    if ((F = fopen(OutName, "w")) == NULL) {
  926. X        Fprintf(stderr, "Can't open '%s' for output, %s.\n",
  927. X            OutName, Ermsg(errno));
  928. X        exit(1);
  929. X    }
  930. X    }
  931. X
  932. X    /* Sort the shipping list, then write it. */
  933. X    if (!Preserve)
  934. X    qsort((char *)Table, lines, sizeof Table[0], NameP);
  935. X    Fprintf(F, "   File Name\t\tArchive #\tDescription\n");
  936. X    Fprintf(F, "-----------------------------------------------------------\n");
  937. X    for (t = Table; t < TabEnd; t++)
  938. X    Fprintf(F, FORMAT1, t->Name, t->Where + 1, t->Text);
  939. X
  940. X    /* Close output.  Are we done? */
  941. X    if (F != stdout)
  942. X    (void)fclose(F);
  943. X    if (!Working)
  944. X    exit(0);
  945. X
  946. X    /* Find last archive number. */
  947. X    for (i = 0, t = Table; t < TabEnd; t++)
  948. X    if (i < t->Where)
  949. X        i = t->Where;
  950. X    LastOne = i + 1;
  951. X
  952. X    /* Find archive with most files in it. */
  953. X    for (i = 0, k = Ark; k < ArkEnd; k++)
  954. X    if (i < k->Count)
  955. X        i = k->Count;
  956. X
  957. X    /* Build the fixed part of the argument vector. */
  958. X    av = NEW(char*, i + 10);
  959. X    av[0] = "shar";
  960. X    i = 1;
  961. X    if (Trailer) {
  962. X    av[i++] = "-t";
  963. X    av[i++] = Trailer;
  964. X    }
  965. X    if (Notkits == FALSE) {
  966. X    (void)sprintf(EndArkNum, "%d", LastOne);
  967. X    av[i++] = "-e";
  968. X    av[i++] = EndArkNum;
  969. X    av[i++] = "-n";
  970. X    av[i++] = CurArkNum;
  971. X    }
  972. X#ifdef    MSDOS
  973. X    av[i++] = "-i";
  974. X    av[i++] = FLST = mktemp("/tmp/manlXXXXXX");
  975. X#endif    /* MSDOS */
  976. X
  977. X    av[i++] = "-o";
  978. X    av[i++] = buff;
  979. X
  980. X    /* Call shar to package up each archive. */
  981. X    for (Start = i, i = 0; i < LastOne; i++) {
  982. X    (void)sprintf(CurArkNum, "%d", i + 1);
  983. X    (void)sprintf(buff, FORMAT2, SharName, i + 1);
  984. X#ifndef    MSDOS
  985. X    for (lines = Start, t = Table; t < TabEnd; t++)
  986. X        if (t->Where == i)
  987. X        av[lines++] = t->Name;
  988. X    av[lines] = NULL;
  989. X#else
  990. X    if ((F = fopen(FLST, "w")) == NULL) {
  991. X        Fprintf(stderr, "Can't open list file '%s' for output, %s.\n",
  992. X            FLST, Ermsg(errno));
  993. X        exit(1);
  994. X    }
  995. X    for (t = Table; t < TabEnd; t++)
  996. X        if (t->Where == i)
  997. X        Fprintf(F, "%s\n", t->Name);
  998. X    (void)fclose(F);
  999. X#endif /* MSDOS */
  1000. X    Fprintf(stderr, "Packing kit %d...\n", i + 1);
  1001. X    if (lines = Execute(av))
  1002. X        Fprintf(stderr, "Warning:  shar returned status %d.\n", lines);
  1003. X    }
  1004. X
  1005. X#ifdef    MSDOS
  1006. X    (void)unlink(FLST);
  1007. X#endif    /* MSDOS */
  1008. X    /* That's all she wrote. */
  1009. X    exit(0);
  1010. X}
  1011. END_OF_FILE
  1012. if test 10488 -ne `wc -c <'makekit.c'`; then
  1013.     echo shar: \"'makekit.c'\" unpacked with wrong size!
  1014. fi
  1015. # end of 'makekit.c'
  1016. fi
  1017. if test -f 'shar.c' -a "${1}" != "-c" ; then 
  1018.   echo shar: Will not clobber existing file \"'shar.c'\"
  1019. else
  1020. echo shar: Extracting \"'shar.c'\" \(7551 characters\)
  1021. sed "s/^X//" >'shar.c' <<'END_OF_FILE'
  1022. X/*
  1023. X**  SHAR
  1024. X**  Make a shell archive of a list of files.
  1025. X*/
  1026. X#include "shar.h"
  1027. X#ifdef    RCSID
  1028. static char RCS[] =
  1029. X    "$Header: shar.c,v 2.0 88/05/27 14:10:47 rsalz Exp $";
  1030. X#endif    /* RCSID */
  1031. X
  1032. X/*
  1033. X**  Minimum allocation of file name pointers used in "-i" option processing.
  1034. X*/
  1035. X#define    MIN_FILES    50
  1036. X
  1037. X
  1038. X/*
  1039. X**  This prolog is output before the archive.
  1040. X*/
  1041. static char     *Prolog[] = {
  1042. X  "! /bin/sh",
  1043. X  " This is a shell archive.  Remove anything before this line, then unpack",
  1044. X  " it by saving it into a file and typing \"sh file\".  To overwrite existing",
  1045. X  " files, type \"sh file -c\".  You can also feed this as standard input via",
  1046. X  " unshar, or by typing \"sh <file\", e.g..  If this archive is complete, you",
  1047. X  " will see the following message at the end:",
  1048. X  NULL
  1049. X};
  1050. X
  1051. X
  1052. X/*
  1053. X**  Package up one file or directory.
  1054. X*/
  1055. static void
  1056. shar(file, Basename)
  1057. X    char        *file;
  1058. X    int             Basename;
  1059. X{
  1060. X    REGISTER char    *s;
  1061. X    REGISTER char    *Name;
  1062. X    REGISTER int     Bads;
  1063. X    REGISTER off_t     Size;
  1064. X    char         buf[BUFSIZ];
  1065. X
  1066. X    /* Just in case. */
  1067. X    if (EQ(file, ".") || EQ(file, ".."))
  1068. X    return;
  1069. X
  1070. X    Size = Fsize(file);
  1071. X    Name =  Basename && (Name = RDX(file, '/')) ? Name + 1 : file;
  1072. X
  1073. X    /* Making a directory? */
  1074. X    if (Ftype(file) == F_DIR) {
  1075. X    Printf("if test ! -d '%s' ; then\n", Name);
  1076. X    Printf("    echo shar: Creating directory \\\"'%s'\\\"\n", Name);
  1077. X    Printf("    mkdir '%s'\n", Name);
  1078. X    Printf("fi\n");
  1079. X    }
  1080. X    else {
  1081. X    if (freopen(file, "r", stdin) == NULL) {
  1082. X        Fprintf(stderr, "Can't open %s, %s\n", file, Ermsg(errno));
  1083. X        exit(1);
  1084. X    }
  1085. X
  1086. X    /* Emit the per-file prolog. */
  1087. X    Printf("if test -f '%s' -a \"${1}\" != \"-c\" ; then \n", Name);
  1088. X    Printf("  echo shar: Will not clobber existing file \\\"'%s'\\\"\n",
  1089. X           Name);
  1090. X    Printf("else\n");
  1091. X    Printf("echo shar: Extracting \\\"'%s'\\\" \\(%ld character%s\\)\n",
  1092. X           Name, (long)Size, Size == 1 ? "" : "s");
  1093. X    Printf("sed \"s/^X//\" >'%s' <<'END_OF_FILE'\n", Name, Name);
  1094. X
  1095. X    /* Output the file contents. */
  1096. X    for (Bads = 0; fgets(buf, BUFSIZ, stdin); )
  1097. X        if (buf[0]) {
  1098. X        if (buf[0] == 'X' || buf[0] == 'E' || buf[0] == 'F'
  1099. X         || !isalpha(buf[0]))
  1100. X            /* Protect non-alpha's, the shar pattern character, the
  1101. X             * END_OF_FILE message, and mail "From" lines. */
  1102. X            (void)putchar('X');
  1103. X        for (s = buf; *s; s++) {
  1104. X            if (BADCHAR(*s))
  1105. X            Bads++;
  1106. X            (void)putchar(*s);
  1107. X        }
  1108. X        }
  1109. X
  1110. X    /* Tell about and control characters. */
  1111. X    Printf("END_OF_FILE\n", Name);
  1112. X    if (Bads) {
  1113. X        Printf(
  1114. X    "echo shar: %d control character%s may be missing from \\\"'%s'\\\"\n",
  1115. X           Bads, Bads == 1 ? "" : "s", Name);
  1116. X        Fprintf(stderr, "Found %d control char%s in \"'%s'\"\n",
  1117. X            Bads, Bads == 1 ? "" : "s", Name);
  1118. X    }
  1119. X
  1120. X    /* Output size check. */
  1121. X    Printf("if test %ld -ne `wc -c <'%s'`; then\n", (long)Size, Name);
  1122. X    Printf("    echo shar: \\\"'%s'\\\" unpacked with wrong size!\n", Name);
  1123. X    Printf("fi\n");
  1124. X
  1125. X    /* Executable? */
  1126. X    if (Fexecute(file))
  1127. X        Printf("chmod +x '%s'\n", Name);
  1128. X
  1129. X    Printf("# end of '%s'\nfi\n", Name);
  1130. X    }
  1131. X}
  1132. X
  1133. X
  1134. X/*
  1135. X**  Read list of files from file.
  1136. X*/
  1137. static char **
  1138. GetFiles(Name)
  1139. X    char         *Name;
  1140. X{
  1141. X    REGISTER FILE     *F;
  1142. X    REGISTER int      i;
  1143. X    REGISTER int      count;
  1144. X    REGISTER char    **files;
  1145. X    REGISTER char    **temp;
  1146. X    REGISTER int      j;
  1147. X    char          buff[BUFSIZ];
  1148. X    char         *p;
  1149. X
  1150. X    /* Open the file. */
  1151. X    if (EQ(Name, "-"))
  1152. X    F = stdin;
  1153. X    else if ((F = fopen(Name, "r")) == NULL) {
  1154. X    Fprintf(stderr, "Can't open '%s' for input.\n", Name);
  1155. X    return(NULL);
  1156. X    }
  1157. X
  1158. X    /* Get space. */
  1159. X    count = MIN_FILES;
  1160. X    files = NEW(char*, count);
  1161. X
  1162. X    /* Read lines. */
  1163. X    for (i = 0; fgets(buff, sizeof buff, F); ) {
  1164. X    if (p = IDX(buff, '\n'))
  1165. X        *p = '\0';
  1166. X    files[i] = COPY(buff);
  1167. X    if (++i == count - 2) {
  1168. X        /* Get more space; some systems don't have realloc()... */
  1169. X        for (count += MIN_FILES, temp = NEW(char*, count), j = 0; j < i; j++)
  1170. X        temp[j] = files[j];
  1171. X        files = temp;
  1172. X    }
  1173. X    }
  1174. X
  1175. X    /* Clean up, close up, return. */
  1176. X    files[i] = NULL;
  1177. X    (void)fclose(F);
  1178. X    return(files);
  1179. X}
  1180. X
  1181. X
  1182. X
  1183. main(ac, av)
  1184. X    int             ac;
  1185. X    REGISTER char    *av[];
  1186. X{
  1187. X    REGISTER char    *Trailer;
  1188. X    REGISTER char    *p;
  1189. X    REGISTER char    *q;
  1190. X    REGISTER int     i;
  1191. X    REGISTER int     length;
  1192. X    REGISTER int     Oops;
  1193. X    REGISTER int     Knum;
  1194. X    REGISTER int     Kmax;
  1195. X    REGISTER int     Basename;
  1196. X    REGISTER int     j;
  1197. X    time_t         clock;
  1198. X    char        **Flist;
  1199. X
  1200. X    /* Parse JCL. */
  1201. X    Basename = 0;
  1202. X    Knum = 0;
  1203. X    Kmax = 0;
  1204. X    Trailer = NULL;
  1205. X    for (Oops = 0; (i = getopt(ac, av, "be:i:n:o:t:")) != EOF; )
  1206. X    switch (i) {
  1207. X    default:
  1208. X        Oops++;
  1209. X        break;
  1210. X    case 'b':
  1211. X        Basename++;
  1212. X        break;
  1213. X    case 'e':
  1214. X        Kmax = atoi(optarg);
  1215. X        break;
  1216. X    case 'i':
  1217. X        Flist = GetFiles(optarg);
  1218. X        break;
  1219. X    case 'n':
  1220. X        Knum = atoi(optarg);
  1221. X        break;
  1222. X    case 'o':
  1223. X        if (freopen(optarg, "w", stdout) == NULL) {
  1224. X        Fprintf(stderr, "Can't open %s for output, %s.\n",
  1225. X            optarg, Ermsg(errno));
  1226. X        Oops++;
  1227. X        }
  1228. X        break;
  1229. X    case 't':
  1230. X        Trailer = optarg;
  1231. X        break;
  1232. X    }
  1233. X
  1234. X    /* Rest of arguments are files. */
  1235. X    if  (Flist == NULL) {
  1236. X    av += optind;
  1237. X    if (*av == NULL) {
  1238. X        Fprintf(stderr, "No input files\n");
  1239. X        Oops++;
  1240. X    }
  1241. X    Flist = av;
  1242. X    }
  1243. X
  1244. X    if (Oops) {
  1245. X    Fprintf(stderr,
  1246. X        "USAGE: shar [-b] [-o:] [-i:] [-n:e:t:] file... >SHAR\n");
  1247. X    exit(1);
  1248. X    }
  1249. X
  1250. X    /* Everything readable and reasonably-named? */
  1251. X    for (Oops = 0, i = 0; p = Flist[i]; i++)
  1252. X    if (freopen(p, "r", stdin) == NULL) {
  1253. X        Fprintf(stderr, "Can't read %s, %s.\n", p, Ermsg(errno));
  1254. X        Oops++;
  1255. X    }
  1256. X    else
  1257. X        for (; *p; p++)
  1258. X        if (!isascii(*p)) {
  1259. X            Fprintf(stderr, "Bad character '%c' in '%s'.\n",
  1260. X                *p, Flist[i]);
  1261. X            Oops++;
  1262. X        }
  1263. X    if (Oops)
  1264. X    exit(2);
  1265. X
  1266. X    /* Prolog. */
  1267. X    for (i = 0; p = Prolog[i]; i++)
  1268. X    Printf("#%s\n", p);
  1269. X    if (Knum && Kmax)
  1270. X    Printf("#\t\t\"End of archive %d (of %d).\"\n", Knum, Kmax);
  1271. X    else
  1272. X        Printf("#\t\t\"End of shell archive.\"\n");
  1273. X    Printf("# Contents: ");
  1274. X    for (length = 12, i = 0; p = Flist[i++]; length += j) {
  1275. X    if (Basename && (q = RDX(p, '/')))
  1276. X        p = q + 1;
  1277. X    j = strlen(p) + 1;
  1278. X    if (length + j < WIDTH)
  1279. X        Printf(" %s", p);
  1280. X    else {
  1281. X        Printf("\n#   %s", p);
  1282. X        length = 4;
  1283. X    }
  1284. X    }
  1285. X    Printf("\n");
  1286. X    clock = time((time_t *)NULL);
  1287. X    Printf("# Wrapped by %s@%s on %s", User(), Host(), ctime(&clock));
  1288. X    Printf("PATH=/bin:/usr/bin:/usr/ucb ; export PATH\n");
  1289. X
  1290. X    /* Do it. */
  1291. X    while (*Flist)
  1292. X    shar(*Flist++, Basename);
  1293. X
  1294. X    /* Epilog. */
  1295. X    if (Knum && Kmax) {
  1296. X    Printf("echo shar: End of archive %d \\(of %d\\).\n", Knum, Kmax);
  1297. X    Printf("cp /dev/null ark%disdone\n", Knum);
  1298. X    Printf("MISSING=\"\"\n");
  1299. X    Printf("for I in");
  1300. X    for (i = 0; i < Kmax; i++)
  1301. X        Printf(" %d", i + 1);
  1302. X    Printf(" ; do\n");
  1303. X    Printf("    if test ! -f ark${I}isdone ; then\n");
  1304. X    Printf("\tMISSING=\"${MISSING} ${I}\"\n");
  1305. X    Printf("    fi\n");
  1306. X    Printf("done\n");
  1307. X    Printf("if test \"${MISSING}\" = \"\" ; then\n");
  1308. X    if (Kmax == 1)
  1309. X        Printf("    echo You have the archive.\n");
  1310. X    else if (Kmax == 2)
  1311. X        Printf("    echo You have unpacked both archives.\n");
  1312. X    else
  1313. X        Printf("    echo You have unpacked all %d archives.\n", Kmax);
  1314. X    if (Trailer && *Trailer)
  1315. X        Printf("    echo \"%s\"\n", Trailer);
  1316. X    Printf("    rm -f ark[1-9]isdone%s\n",
  1317. X           Kmax >= 9 ? " ark[1-9][0-9]isdone" : "");
  1318. X    Printf("else\n");
  1319. X    Printf("    echo You still need to unpack the following archives:\n");
  1320. X    Printf("    echo \"        \" ${MISSING}\n");
  1321. X    Printf("fi\n");
  1322. X    Printf("##  End of shell archive.\n");
  1323. X    }
  1324. X    else {
  1325. X        Printf("echo shar: End of shell archive.\n");
  1326. X    if (Trailer && *Trailer)
  1327. X        Printf("echo \"%s\"\n", Trailer);
  1328. X    }
  1329. X
  1330. X    Printf("exit 0\n");
  1331. X
  1332. X    exit(0);
  1333. X}
  1334. END_OF_FILE
  1335. if test 7551 -ne `wc -c <'shar.c'`; then
  1336.     echo shar: \"'shar.c'\" unpacked with wrong size!
  1337. fi
  1338. # end of 'shar.c'
  1339. fi
  1340. if test -f 'unshar.c' -a "${1}" != "-c" ; then 
  1341.   echo shar: Will not clobber existing file \"'unshar.c'\"
  1342. else
  1343. echo shar: Extracting \"'unshar.c'\" \(8368 characters\)
  1344. sed "s/^X//" >'unshar.c' <<'END_OF_FILE'
  1345. X/*
  1346. X**  UNSHAR
  1347. X**  Unpack shell archives that might have gone through mail, notes, news, etc.
  1348. X**  This is Michael Mauldin's code which I have usurped and heavily modified.
  1349. X*/
  1350. X#include "shar.h"
  1351. X#ifdef    RCSID
  1352. static char RCS[] =
  1353. X    "$Header: unshar.c,v 2.0 88/05/27 13:28:13 rsalz Exp $";
  1354. X#endif    /* RCSID */
  1355. X
  1356. X
  1357. X/*
  1358. X**  Print error message and die.
  1359. X*/
  1360. static void
  1361. Quit(text)
  1362. X    char    *text;
  1363. X{
  1364. X    int         e;
  1365. X
  1366. X    e = errno;
  1367. X    Fprintf(stderr, "unshar:  %s", text);
  1368. X    if (e)
  1369. X    Fprintf(stderr, ", %s", Ermsg(e));
  1370. X    Fprintf(stderr, ".\n");
  1371. X    exit(1);
  1372. X}
  1373. X
  1374. X
  1375. X/*
  1376. X**  Does this look like a mail header line?
  1377. X*/
  1378. static int
  1379. IsHeader(p)
  1380. X    REGISTER char    *p;
  1381. X{
  1382. X    REGISTER int     i;
  1383. X
  1384. X    if (*p == '\0' || *p == '\n')
  1385. X    return(FALSE);
  1386. X    if (WHITE(*p))
  1387. X    return(TRUE);
  1388. X    for (i = 0; *p == '-' || *p == '_' || *p == '.' || isalnum(*p); i++)
  1389. X    p++;
  1390. X    return(i && *p == ':');
  1391. X}
  1392. X
  1393. X
  1394. X/*
  1395. X**  Is this a /bin/sh comment line?  We check that because some shars
  1396. X**  output comments before the CUT line.
  1397. X*/
  1398. static int
  1399. IsSHcomment(p)
  1400. X    REGISTER char    *p;
  1401. X{
  1402. X    while (isalpha(*p) || WHITE(*p) || *p == '\n' || *p == ',' || *p == '.')
  1403. X    p++;
  1404. X    return(*p == '\0');
  1405. X}
  1406. X
  1407. X
  1408. X/*
  1409. X**  Return TRUE if p has wd1 and wd2 as words (i.e., no preceeding or
  1410. X**  following letters).  Clever code, Michael.
  1411. X*/
  1412. static int
  1413. Has(p, wd1, wd2)
  1414. X    REGISTER char    *p;
  1415. X    REGISTER char    *wd1;
  1416. X    REGISTER char    *wd2;
  1417. X{
  1418. X    REGISTER char    *wd;
  1419. X    REGISTER int     first;
  1420. X
  1421. X    wd = wd1;
  1422. X    first = TRUE;
  1423. again: 
  1424. X    while (*p) {
  1425. X    if (!isalpha(*p)) {
  1426. X        p++;
  1427. X        continue;
  1428. X    }
  1429. X    while (*p++ == *wd++) {
  1430. X        if (*wd == '\0') {
  1431. X        if (!isalpha(*p)) {
  1432. X            if (!first)
  1433. X            return(TRUE);
  1434. X            first = FALSE;
  1435. X            wd = wd2;
  1436. X            goto again;
  1437. X        }
  1438. X        break;
  1439. X        }
  1440. X    }
  1441. X    while (isalpha(*p))
  1442. X        p++;
  1443. X    wd = first ? wd1 : wd2;
  1444. X    }
  1445. X    return(FALSE);
  1446. X}
  1447. X
  1448. X
  1449. X/*
  1450. X**  Here's where the work gets done.  Skip headers and try to intuit
  1451. X**  if the file is, e.g., C code, etc.
  1452. X*/
  1453. static int
  1454. XFound(Name, buff, Forced, Stream, Header)
  1455. X    REGISTER char    *Name;
  1456. X    REGISTER char    *buff;
  1457. X    REGISTER int     Forced;
  1458. X    REGISTER FILE    *Stream;
  1459. X    REGISTER FILE    *Header;
  1460. X{
  1461. X    REGISTER char    *p;
  1462. X    REGISTER int     InHeader;
  1463. X    char         lower[BUFSIZ];
  1464. X
  1465. X    if (Header)
  1466. X    InHeader = TRUE;
  1467. X
  1468. X    while (TRUE) {
  1469. X    /* Read next line, fail if no more */
  1470. X    if (fgets(buff, BUFSIZ, Stream) == NULL) {
  1471. X        Fprintf(stderr, "unshar:  No shell commands in %s.\n", Name);
  1472. X        return(FALSE);
  1473. X    }
  1474. X
  1475. X    /* See if it looks like another language. */
  1476. X    if (!Forced) {
  1477. X        if (PREFIX(buff, "#include") || PREFIX(buff, "# include")
  1478. X         || PREFIX(buff, "#define") || PREFIX(buff, "# define")
  1479. X         || PREFIX(buff, "#ifdef") || PREFIX(buff, "# ifdef")
  1480. X         || PREFIX(buff, "#ifndef") || PREFIX(buff, "# ifndef")
  1481. X         || (PREFIX(buff, "/*")
  1482. X          && !PREFIX(buff, NOTES1) && !PREFIX(buff, NOTES2)))
  1483. X        p = "C code";
  1484. X        else if (PREFIX(buff, "(*"))        /* For vi :-) */
  1485. X        p = "PASCAL code";
  1486. X        else if (buff[0] == '.' && isalpha(buff[1]) && isalpha(buff[2])
  1487. X          && !isalpha(buff[3]))
  1488. X        p = "TROFF source";
  1489. X        else
  1490. X        p = NULL;
  1491. X        if (p) {
  1492. X        Fprintf(stderr,
  1493. X            "unshar:  %s is apparently %s, not a shell archive.\n",
  1494. X            Name, p);
  1495. X        return(FALSE);
  1496. X        }
  1497. X    }
  1498. X
  1499. X    /* Does this line start with a shell command or comment? */
  1500. X    if ((buff[0] == '#' && !IsSHcomment(buff + 1))
  1501. X     || buff[0] == ':' || PREFIX(buff, "echo ")
  1502. X     || PREFIX(buff, "sed ") || PREFIX(buff, "cat ")) {
  1503. X        return(TRUE);
  1504. X    }
  1505. X
  1506. X    /* Does this line say "Cut here"? */
  1507. X    for (p = strcpy(lower, buff); *p; p++)
  1508. X        if (isascii(*p) && islower(*p))
  1509. X        *p = toupper(*p);
  1510. X    if (PREFIX(buff, "-----") || Has(lower, "cut", "here")
  1511. X     || Has(lower, "cut", "cut") || Has(lower, "tear", "here")) {
  1512. X        /* Get next non-blank line. */
  1513. X        do {
  1514. X        if (fgets(buff, BUFSIZ, Stream) == NULL) {
  1515. X            Fprintf(stderr, "unshar:  cut line is last line of %s\n",
  1516. X                Name);
  1517. X            return(FALSE);
  1518. X        }
  1519. X        } while (*buff == '\n');
  1520. X
  1521. X        /* If it starts with a comment or lower-case letter we win. */
  1522. X        if (*buff == '#' || *buff == ':' || islower(*buff))
  1523. X        return(TRUE);
  1524. X
  1525. X        /* The cut message lied. */
  1526. X        Fprintf(stderr, "unshar: %s is not a shell archive,\n", Name);
  1527. X        Fprintf(stderr, "        the 'cut' line was followed by: %s", buff);
  1528. X        return(FALSE);
  1529. X    }
  1530. X
  1531. X    if (Header) {
  1532. X        (void)fputs(buff, Header);
  1533. X        if (InHeader && !IsHeader(buff))
  1534. X        InHeader = FALSE;
  1535. X    }
  1536. X    }
  1537. X}
  1538. X
  1539. X
  1540. X/*
  1541. X**  Create file for the header, find true start of the archive,
  1542. X**  and send it off to the shell.
  1543. X*/
  1544. static void
  1545. Unshar(Name, HdrFile, Stream, Saveit, Forced)
  1546. X    char        *Name;
  1547. X    char        *HdrFile;
  1548. X    REGISTER FILE     *Stream;
  1549. X    int             Saveit;
  1550. X    int             Forced;
  1551. X{
  1552. X    REGISTER FILE    *Header;
  1553. X#ifndef    USE_MY_SHELL
  1554. X    REGISTER FILE    *Pipe;
  1555. X#endif    /* USE_MY_SHELL */
  1556. X    char        *p;
  1557. X    char         buff[BUFSIZ];
  1558. X
  1559. X    if (Saveit) {
  1560. X    /* Create a name for the saved header. */
  1561. X    if (HdrFile)
  1562. X        (void)strcpy(buff, HdrFile);
  1563. X    else if (Name) {
  1564. X        p = RDX(Name, '/');
  1565. X        (void)strncpy(buff, p ? p + 1 : Name, 14);
  1566. X        buff[10] = 0;
  1567. X        (void)strcat(buff, ".hdr");
  1568. X    }
  1569. X    else
  1570. X        (void)strcpy(buff, "UNSHAR.HDR");
  1571. X
  1572. X    /* Tell user, and open the file. */
  1573. X    Fprintf(stderr, "unshar:  Sending header to %s.\n", buff);
  1574. X    if ((Header = fopen(buff, "a")) == NULL)
  1575. X        Quit("Can't open file for header");
  1576. X    }
  1577. X    else
  1578. X    Header = NULL;
  1579. X
  1580. X    /* If name is NULL, we're being piped into... */
  1581. X    p = Name ? Name : "the standard input";
  1582. X    Printf("unshar:  Doing %s:\n", p);
  1583. X
  1584. X    if (Found(p, buff, Forced, Stream, Header)) {
  1585. X#ifdef    USE_MY_SHELL
  1586. X    BinSh(Name, Stream, buff);
  1587. X#else
  1588. X    if ((Pipe = popen("/bin/sh", "w")) == NULL)
  1589. X        Quit("Can't open pipe to /bin/sh process");
  1590. X
  1591. X    (void)fputs(buff, Pipe);
  1592. X    while (fgets(buff, sizeof buff, Stream))
  1593. X        (void)fputs(buff, Pipe);
  1594. X
  1595. X    (void)pclose(Pipe);
  1596. X#endif    /* USE_MY_SHELL */
  1597. X    }
  1598. X
  1599. X    /* Close the headers. */
  1600. X    if (Saveit)
  1601. X    (void)fclose(Header);
  1602. X}
  1603. X
  1604. X
  1605. main(ac, av)
  1606. X    REGISTER int     ac;
  1607. X    REGISTER char    *av[];
  1608. X{
  1609. X    REGISTER FILE    *Stream;
  1610. X    REGISTER int     i;
  1611. X    char        *p;
  1612. X    char        *HdrFile;
  1613. X    char         cwd[BUFSIZ];
  1614. X    char         dir[BUFSIZ];
  1615. X    char         buff[BUFSIZ];
  1616. X    int             Saveit;
  1617. X    int             Forced;
  1618. X
  1619. X    /* Parse JCL. */
  1620. X    p = getenv("UNSHARDIR");
  1621. X    Saveit = DEF_SAVEIT;
  1622. X    HdrFile = NULL;
  1623. X    for (Forced = 0; (i = getopt(ac, av, "c:d:fh:ns")) != EOF; )
  1624. X    switch (i) {
  1625. X    default:
  1626. X        Quit("Usage: unshar [-fs] [-c dir] [-h hdrfile] [input files]");
  1627. X        /* NOTREACHED */
  1628. X    case 'c': 
  1629. X    case 'd': 
  1630. X        p = optarg;
  1631. X        break;
  1632. X    case 'f':
  1633. X        Forced++;
  1634. X        break;
  1635. X    case 'h':
  1636. X        HdrFile = optarg;
  1637. X        /* FALLTHROUGH */
  1638. X    case 's': 
  1639. X        Saveit = TRUE;
  1640. X        break;
  1641. X    case 'n':
  1642. X        Saveit = FALSE;
  1643. X        break;
  1644. X    }
  1645. X    av += optind;
  1646. X
  1647. X    /* Going somewhere? */
  1648. X    if (p) {
  1649. X    if (*p == '?') {
  1650. X        /* Ask for name; go to THE_TTY if we're being piped into. */
  1651. X        Stream = isatty(fileno(stdin)) ? stdin : fopen(THE_TTY, "r");
  1652. X        if (Stream == NULL)
  1653. X        Quit("Can't open tty to ask for directory");
  1654. X        Printf("unshar:  what directory?  ");
  1655. X        (void)fflush(stdout);
  1656. X        if (fgets(buff, sizeof buff, Stream) == NULL
  1657. X         || buff[0] == '\n'
  1658. X         || (p = IDX(buff, '\n')) == NULL)
  1659. X        Quit("Okay, cancelled");
  1660. X        *p = '\0';
  1661. X        p = buff;
  1662. X        if (Stream != stdin)
  1663. X        (void)fclose(Stream);
  1664. X    }
  1665. X
  1666. X    /* If name is ~/blah, he means $HOME/blah. */
  1667. X    if (*p == '~') {
  1668. X        if (getenv("HOME") == NULL)
  1669. X        Quit("You have no $HOME?");
  1670. X        (void)sprintf(dir, "%s/%s", getenv("HOME"), p + 1);
  1671. X        p = dir;
  1672. X    }
  1673. X
  1674. X    /* If we're gonna move, first remember where we were. */
  1675. X    if (Cwd(cwd, sizeof cwd) == NULL) {
  1676. X        Fprintf(stderr, "unshar warning:  Can't get current directory.\n");
  1677. X        cwd[0] = '\0';
  1678. X    }
  1679. X
  1680. X    /* Got directory; try to go there.  Only make last component. */
  1681. X    if (chdir(p) < 0 && mkdir(p, 0777) < 0 && chdir(p) < 0)
  1682. X        Quit("Cannot chdir nor mkdir desired directory");
  1683. X    }
  1684. X    else
  1685. X    cwd[0] = '\0';
  1686. X
  1687. X    /* No buffering. */
  1688. X    (void)setbuf(stdout, (char *)NULL);
  1689. X    (void)setbuf(stderr, (char *)NULL);
  1690. X
  1691. X    if (*av)
  1692. X    /* Process filenames from command line. */
  1693. X    for (; *av; av++) {
  1694. X        if (cwd[0] && av[0][0] != '/') {
  1695. X        (void)sprintf(buff, "%s/%s", cwd, *av);
  1696. X        *av = buff;
  1697. X        }
  1698. X        if ((Stream = fopen(*av, "r")) == NULL)
  1699. X        Fprintf(stderr, "unshar:  Can't open file '%s'.\n", *av);
  1700. X        else {
  1701. X        Unshar(*av, HdrFile, Stream, Saveit, Forced);
  1702. X        (void)fclose(Stream);
  1703. X        }
  1704. X    }
  1705. X    else
  1706. X    /* Do standard input. */
  1707. X    Unshar((char *)NULL, HdrFile, stdin, Saveit, Forced);
  1708. X
  1709. X    /* That's all she wrote. */
  1710. X    exit(0);
  1711. X}
  1712. END_OF_FILE
  1713. if test 8368 -ne `wc -c <'unshar.c'`; then
  1714.     echo shar: \"'unshar.c'\" unpacked with wrong size!
  1715. fi
  1716. # end of 'unshar.c'
  1717. fi
  1718. echo shar: End of archive 2 \(of 3\).
  1719. cp /dev/null ark2isdone
  1720. MISSING=""
  1721. for I in 1 2 3 ; do
  1722.     if test ! -f ark${I}isdone ; then
  1723.     MISSING="${MISSING} ${I}"
  1724.     fi
  1725. done
  1726. if test "${MISSING}" = "" ; then
  1727.     echo You have unpacked all 3 archives.
  1728.     echo "See the README"
  1729.     rm -f ark[1-9]isdone
  1730. else
  1731.     echo You still need to unpack the following archives:
  1732.     echo "        " ${MISSING}
  1733. fi
  1734. ##  End of shell archive.
  1735. exit 0
  1736.